﻿Imports AutoCAD

Public Class CadBlockReferenceServiceImpl
    Implements ICadBlockReferenceService
    Public cadApplicationService As ICadApplicationService = New CadApplicationServiceImpl
    Public Shared ZeroPoint As Double() = New Double() {0, 0, 0} '零点
    Public Shared XAxis As Double() = New Double() {1, 0, 0} 'X轴
    Public Shared YAxis As Double() = New Double() {0, 1, 0} 'Y轴
    Public Shared ZAxis As Double() = New Double() {0, 0, 1} 'Z轴

    Public Function GetOCS(ByRef br As AcadBlockReference) As AcadUCS Implements ICadBlockReferenceService.GetOCS
        Dim doc As AcadDocument = br.Document
        Dim n As Double() = br.Normal
        Dim 反转 As Double = IIf(IsMirror(br), -1, 1) ' 判断是否为镜像, 如果为镜像则返回负值

        ' 根据块旋转x与y轴
        Dim _XAxis As Double() = cadApplicationService.Rotate2D(XAxis, -br.Rotation * 1)
        Dim _YAxis As Double() = cadApplicationService.Rotate2D(YAxis, -br.Rotation * 1)

        ' 适应块的法线
        _XAxis = doc.Utility.TranslateCoordinates(_XAxis, AcCoordinateSystem.acOCS, AcCoordinateSystem.acWorld, False, br.Normal)
        _YAxis = doc.Utility.TranslateCoordinates(_YAxis, AcCoordinateSystem.acOCS, AcCoordinateSystem.acWorld, False, br.Normal)

        ' 构建ocs
        Dim ucs As AcadUCS = doc.UserCoordinateSystems.Add(ZeroPoint, _XAxis, _YAxis, $"ucs_{br.EffectiveName}")
        'doc.ActiveUCS = ucs
        Return ucs
    End Function

    Public Function GetBlock(ByRef br As AcadBlock) As AcadBlock Implements ICadBlockReferenceService.GetBlock
        Dim doc As AcadDocument = br.Document
        Return doc.Blocks.Item(br.Name)
    End Function

    Public Function GetBBox(ByRef ent As AcadEntity) As Double(,) Implements ICadEntityService.GetBBox
        Dim minp As Object, maxp As Object
        ent.GetBoundingBox(minp, maxp)

        Dim bbox(1, 2) As Double
        bbox(0, 0) = minp(0)
        bbox(0, 1) = minp(1)
        bbox(0, 2) = minp(2)
        bbox(1, 0) = maxp(0)
        bbox(1, 1) = maxp(1)
        bbox(1, 2) = maxp(2)

        Return bbox
    End Function


    Public Function GetCentroid(ByRef ent As AcadEntity) As Double() Implements ICadEntityService.GetCentroid

        Dim bbox(,) = GetBBox(ent)
        Dim centroid(2) As Double
        centroid(0) = Math.Round(bbox(0, 0) + bbox(1, 0) / 2, 6)
        centroid(0) = Math.Round(bbox(0, 1) + bbox(1, 1) / 2, 6)
        centroid(0) = Math.Round(bbox(0, 2) + bbox(1, 2) / 2, 6)

        Return centroid
    End Function

    Public Function IsMirror(ByRef br As AcadBlockReference) As Boolean Implements ICadBlockReferenceService.IsMirror
        Return br.XScaleFactor < 0
    End Function

    Public Sub 镜像法线(ByRef br As AcadBlockReference) Implements ICadBlockReferenceService.镜像法线
        Dim position() As Double = br.InsertionPoint
        br.InsertionPoint = ZeroPoint

        Dim normal As Double() = br.Normal
        normal(0) = normal(0) * -1
        normal(1) = normal(1) * -1
        normal(2) = normal(2) * -1

        br.Normal = normal
        br.Rotation = Math.PI - br.Rotation
        br.InsertionPoint = position
    End Sub


    ''' <summary>
    ''' 旋转块对象
    ''' </summary>
    ''' <param name="br"></param>
    ''' <param name="r"></param>
    Public Sub Rotation(ByRef br As AcadBlockReference, ByRef r() As Double) Implements ICadBlockReferenceService.Rotation
        Dim a As Double = Math.PI / 180
        Dim position() As Double = br.InsertionPoint
        Dim angle As Double() = New Double() {r(0) * a, r(1) * a, r(2) * a}
        With br
            .InsertionPoint = New Double() {0, 0, 0}
            .Rotate3D(New Double() {0, 0, 0}, New Double() {1, 0, 0}, angle(0))
            .Rotate3D(New Double() {0, 0, 0}, New Double() {0, 1, 0}, angle(1))
            .Rotate3D(New Double() {0, 0, 0}, New Double() {0, 0, 1}, angle(2))
            .InsertionPoint = position
        End With
    End Sub




















    Public Sub CopyObjectsToBlock(ByRef br As AcadBlockReference, ByRef ents As IEnumerable) Implements ICadBlockReferenceService.CopyObjectsToBlock

        ' 根据br移动变化各个图元位置
        Dim lt As New List(Of AcadEntity)
        For Each ent As AcadEntity In ents
            With ent
                .Move(br.InsertionPoint, ZeroPoint) '移动
                .TransformBy(GetOCS2(br).GetUCSMatrix) '转换坐标系
                .Rotate(ZeroPoint, br.Rotation * -1) '旋转
            End With
            lt.Add(ent)
        Next ent

        ' 将图元集合复制到块引用中
        Dim doc As AcadDocument = br.Document

        doc.CopyObjects(lt.ToArray, doc.Blocks.Item(br.EffectiveName))

        For Each ent As AcadEntity In ents
            ent.Delete()
        Next
    End Sub

    Public Function GetOCS2(ByRef br As AcadBlockReference) As AcadUCS Implements ICadBlockReferenceService.GetOCS2
        Dim doc As AcadDocument = br.Document
        Dim x() As Double, y() As Double
        With doc.Utility
            x = .TranslateCoordinates(XAxis, AcCoordinateSystem.acWorld, AcCoordinateSystem.acOCS, 0, br.Normal)
            y = .TranslateCoordinates(YAxis, AcCoordinateSystem.acWorld, AcCoordinateSystem.acOCS, 0, br.Normal)
        End With
        Return doc.UserCoordinateSystems.Add(ZeroPoint, x, y, "ucs1")
    End Function

    Public Sub MoveObjectsToBlockReference(ByRef br As AcadBlockReference, ByRef ents As IEnumerable) Implements ICadBlockReferenceService.MoveObjectsToBlockReference
        ' 根据br移动变化各个图元位置
        Dim doc As AcadDocument = br.Document
        Dim ucs As AcadUCS = GetOCS(br)
        For Each ent As AcadEntity In ents
            With ent
                .TransformBy(ucs.GetUCSMatrix) '转换坐标系
                .Move(ZeroPoint, br.InsertionPoint) '移动
            End With
        Next ent
    End Sub
End Class
